home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 November / november_2001.iso / Browsers / Netscape 6.1 / browser.xpi / bin / chrome / comm.jar / content / editor / EdTableProps.js < prev    next >
Encoding:
JavaScript  |  2001-07-10  |  37.1 KB  |  1,273 lines

  1. /*
  2.  * The contents of this file are subject to the Netscape Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/NPL/
  6.  *
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  *
  12.  * The Original Code is Mozilla Communicator client code, released
  13.  * March 31, 1998.
  14.  *
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation. Portions created by Netscape are
  17.  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
  18.  * Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *    Ben Goodger
  22.  */
  23.  
  24. //Cancel() is in EdDialogCommon.js
  25. var tagname = "table"
  26. var TableElement;
  27. var CellElement;
  28. var TableCaptionElement;
  29. var TabPanels;
  30. var dialog;
  31. var globalCellElement;
  32. var globalTableElement
  33. var TablePanel = 0;
  34. var CellPanel = 1;
  35. var currentPanel = TablePanel;
  36. var validatePanel;
  37. var defHAlign =   "left";
  38. var centerStr =   "center";  //Index=1
  39. var rightStr =    "right";   // 2
  40. var justifyStr =  "justify"; // 3
  41. var charStr =     "char";    // 4
  42. var defVAlign =   "middle";
  43. var topStr =      "top";
  44. var bottomStr =   "bottom";
  45. var bgcolor = "bgcolor";
  46. var TableColor;
  47. var CellColor;
  48.  
  49. var rowCount = 1;
  50. var colCount = 1;
  51. var lastRowIndex;
  52. var lastColIndex;
  53. var newRowCount;
  54. var newColCount;
  55. var curRowIndex;
  56. var curColIndex;
  57. var curColSpan;
  58. var SelectedCellsType = 1;
  59. var SELECT_CELL = 1;
  60. var SELECT_ROW = 2;
  61. var SELECT_COLUMN = 3;
  62. var RESET_SELECTION = 0;
  63. var cellData = new Object;
  64. var AdvancedEditUsed;
  65. var alignWasChar = false;
  66.  
  67. /*
  68. From C++:
  69.  0 TABLESELECTION_TABLE
  70.  1 TABLESELECTION_CELL   There are 1 or more cells selected
  71.                           but complete rows or columns are not selected
  72.  2 TABLESELECTION_ROW    All cells are in 1 or more rows
  73.                           and in each row, all cells selected
  74.                           Note: This is the value if all rows (thus all cells) are selected
  75.  3 TABLESELECTION_COLUMN All cells are in 1 or more columns
  76. */
  77.  
  78. var gSelectedCellCount = 0;
  79. var ApplyUsed = false;
  80. // What should these be?
  81. var maxRows    = 1000; // This is the value gecko code uses for maximum rowspan, colspan
  82. var maxColumns = 1000;
  83. var selection;
  84. var CellDataChanged = false;
  85. var canDelete = false;
  86.  
  87. // dialog initialization code
  88. function Startup()
  89. {
  90.   if (!InitEditorShell()) return;
  91.  
  92.   selection = editorShell.editorSelection;
  93.   if (!selection) return;
  94.  
  95.   dialog = new Object;
  96.   if (!dialog)
  97.   {
  98.     window.close();
  99.     return;
  100.   }
  101.   // Get dialog widgets - Table Panel
  102.   dialog.TableRowsInput = document.getElementById("TableRowsInput");
  103.   dialog.TableColumnsInput = document.getElementById("TableColumnsInput");
  104.   dialog.TableWidthInput = document.getElementById("TableWidthInput");
  105.   dialog.TableWidthUnits = document.getElementById("TableWidthUnits");
  106.   dialog.BorderWidthInput = document.getElementById("BorderWidthInput");
  107.   dialog.SpacingInput = document.getElementById("SpacingInput");
  108.   dialog.PaddingInput = document.getElementById("PaddingInput");
  109.   dialog.TableAlignList = document.getElementById("TableAlignList");
  110.   dialog.TableCaptionList = document.getElementById("TableCaptionList");
  111.   dialog.TableInheritColor = document.getElementById("TableInheritColor");
  112.  
  113.   // Cell Panel
  114.   dialog.SelectionList = document.getElementById("SelectionList");
  115.   dialog.PreviousButton = document.getElementById("PreviousButton");
  116.   dialog.NextButton = document.getElementById("NextButton");
  117.   // Currently, we always apply changes and load new attributes when changing selection
  118.   // (Let's keep this for possible future use)
  119.   //dialog.ApplyBeforeMove =  document.getElementById("ApplyBeforeMove");
  120.   //dialog.KeepCurrentData = document.getElementById("KeepCurrentData");
  121.  
  122.   dialog.CellHeightInput = document.getElementById("CellHeightInput");
  123.   dialog.CellHeightUnits = document.getElementById("CellHeightUnits");
  124.   dialog.CellWidthInput = document.getElementById("CellWidthInput");
  125.   dialog.CellWidthUnits = document.getElementById("CellWidthUnits");
  126.   dialog.CellHAlignList = document.getElementById("CellHAlignList");
  127.   dialog.CellVAlignList = document.getElementById("CellVAlignList");
  128.   dialog.CellInheritColor = document.getElementById("CellInheritColor");
  129.   dialog.CellStyleList = document.getElementById("CellStyleList");
  130.   dialog.TextWrapList = document.getElementById("TextWrapList");
  131.  
  132.   // In cell panel, user must tell us which attributes to apply via checkboxes,
  133.   //  else we would apply values from one cell to ALL in selection
  134.   //  and that's probably not what they expect!
  135.   dialog.CellHeightCheckbox = document.getElementById("CellHeightCheckbox");
  136.   dialog.CellWidthCheckbox = document.getElementById("CellWidthCheckbox");
  137.   dialog.CellHAlignCheckbox = document.getElementById("CellHAlignCheckbox");
  138.   dialog.CellVAlignCheckbox = document.getElementById("CellVAlignCheckbox");
  139.   dialog.CellStyleCheckbox = document.getElementById("CellStyleCheckbox");
  140.   dialog.TextWrapCheckbox = document.getElementById("TextWrapCheckbox");
  141.   dialog.CellColorCheckbox = document.getElementById("CellColorCheckbox");
  142.  
  143.   TabPanels = document.getElementById("TabPanels");
  144.   var TableTab = document.getElementById("TableTab");
  145.   var CellTab = document.getElementById("CellTab");
  146.  
  147.   TableElement = editorShell.GetElementOrParentByTagName("table", null);
  148.   if(!TableElement)
  149.   {
  150.     dump("Failed to get table element!\n");
  151.     window.close();
  152.     return;
  153.   }
  154.   globalTableElement = TableElement.cloneNode(false);
  155.  
  156.   var tagNameObj = new Object;
  157.   var countObj = new Object;
  158.   var tableOrCellElement = editorShell.GetSelectedOrParentTableElement(tagNameObj, countObj);
  159.   gSelectedCellCount = countObj.value;
  160.  
  161.   if (tagNameObj.value == "td")
  162.   {
  163.     // We are in a cell
  164.     CellElement = tableOrCellElement;
  165.     globalCellElement = CellElement.cloneNode(false);
  166.  
  167.     // Tells us whether cell, row, or column is selected
  168.     SelectedCellsType = editorShell.GetSelectedCellsType(TableElement);
  169.  
  170.     // Ignore types except Cell, Row, and Column
  171.     if (SelectedCellsType < SELECT_CELL || SelectedCellsType > SELECT_COLUMN)
  172.       SelectedCellsType = SELECT_CELL;
  173.  
  174.     // Be sure at least 1 cell is selected.
  175.     // (If the count is 0, then we were inside the cell.)
  176.     if (gSelectedCellCount == 0)
  177.       DoCellSelection();
  178.  
  179.     // Get location in the cell map
  180.     curRowIndex = editorShell.GetRowIndex(CellElement);
  181.     curColIndex = editorShell.GetColumnIndex(CellElement);
  182.  
  183.     // We save the current colspan to quickly
  184.     //  move selection from from cell to cell
  185.     if (GetCellData(curRowIndex, curColIndex))
  186.       curColSpan = cellData.colSpan;
  187.  
  188.     // Starting TabPanel name is passed in
  189.     if (window.arguments[1] == "CellPanel")
  190.     {
  191.       currentPanel = CellPanel;
  192.  
  193.       //Set index for starting panel on the <tabpanels> element
  194.       TabPanels.setAttribute("index", CellPanel);
  195.  
  196.       // Trigger setting of style for the tab widgets
  197.       CellTab.setAttribute("selected", "true");
  198.       TableTab.removeAttribute("selected");
  199.  
  200.       // Use cell element for Advanced Edit dialog
  201.       globalElement = globalCellElement;
  202.     }
  203.   }
  204.  
  205.   if (currentPanel == TablePanel)
  206.   {
  207.     // Use table element for Advanced Edit dialog
  208.     globalElement = globalTableElement;
  209.  
  210.     // We may call this with table selected, but no cell,
  211.     //  so disable the Cell Properties tab
  212.     if(!CellElement)
  213.     {
  214.       // XXX: Disabling of tabs is currently broken, so for
  215.       //      now we'll just remove the tab completely.
  216.       //CellTab.setAttribute("disabled", "true");
  217.       CellTab.parentNode.removeChild(CellTab);
  218.     }
  219.   }
  220.  
  221.   doSetOKCancel(onOK, onCancel, 0, onApply);
  222.  
  223.   // Note: we must use TableElement, not globalTableElement for these,
  224.   //  thus we should not put this in InitDialog.
  225.   // Instead, monitor desired counts with separate globals
  226.   rowCount = editorShell.GetTableRowCount(TableElement);
  227.   lastRowIndex = rowCount-1;
  228.   colCount = editorShell.GetTableColumnCount(TableElement);
  229.   lastColIndex = colCount-1;
  230.  
  231.  
  232.   // Set appropriate icons and enable state for the Previous/Next buttons
  233.   SetSelectionButtons();
  234.  
  235.   // If only one cell in table, disable change-selection widgets
  236.   if (rowCount == 1 && colCount == 1)
  237.     dialog.SelectionList.setAttribute("disabled", "true");
  238.  
  239.   // User can change these via textboxes
  240.   newRowCount = rowCount;
  241.   newColCount = colCount;
  242.  
  243.   // This flag is used to control whether set check state
  244.   //  on "set attribute" checkboxes
  245.   // (Advanced Edit dialog use calls  InitDialog when done)
  246.   AdvancedEditUsed = false;
  247.   InitDialog();
  248.   AdvancedEditUsed = true;
  249.  
  250.   // If first initializing, we really aren't changing anything
  251.   CellDataChanged = false;
  252.  
  253.   if (currentPanel == CellPanel)
  254.     dialog.SelectionList.focus();
  255.   else
  256.     SetTextboxFocus(dialog.TableRowsInput);
  257.  
  258.   SetWindowLocation();
  259. }
  260.  
  261.  
  262. function InitDialog()
  263. {
  264. // turn on Button3 to be "apply"
  265.   var applyButton = document.getElementById("Button3");
  266.   if (applyButton)
  267.   {
  268.     applyButton.label = GetString("Apply");
  269.     applyButton.removeAttribute("collapsed");
  270.   }
  271.   
  272.   // Get Table attributes
  273.   dialog.TableRowsInput.value = rowCount;
  274.   dialog.TableColumnsInput.value = colCount;
  275.   dialog.TableWidthInput.value = InitPixelOrPercentMenulist(globalTableElement, TableElement, "width", "TableWidthUnits", gPercent);
  276.   dialog.BorderWidthInput.value = globalTableElement.border;
  277.   dialog.SpacingInput.value = globalTableElement.cellSpacing;
  278.   dialog.PaddingInput.value = globalTableElement.cellPadding;
  279.  
  280.   //BUG: The align strings are converted: e.g., "center" becomes "Center";
  281.   var halign = globalTableElement.align.toLowerCase();
  282.   if (halign == centerStr)
  283.     dialog.TableAlignList.selectedIndex = 1;
  284.   else if (halign == rightStr)
  285.     dialog.TableAlignList.selectedIndex = 2;
  286.   else // Default = left
  287.     dialog.TableAlignList.selectedIndex = 0;
  288.  
  289.   // Be sure to get caption from table in doc, not the copied "globalTableElement"
  290.   TableCaptionElement = TableElement.caption;
  291.   var index = 0;
  292.   if (TableCaptionElement)
  293.   {
  294.     // Note: Other possible values are "left" and "right",
  295.     //  but "align" is deprecated, so should we even support "botton"?
  296.     if (TableCaptionElement.vAlign == "bottom")
  297.       index = 2;
  298.     else
  299.       index = 1;
  300.   }
  301.   dialog.TableCaptionList.selectedIndex = index;
  302.  
  303.   TableColor = globalTableElement.bgColor;
  304.   SetColor("tableBackgroundCW", TableColor);
  305.  
  306.   InitCellPanel();
  307. }
  308.  
  309. function InitCellPanel()
  310. {
  311.   // Get cell attributes
  312.   if (globalCellElement)
  313.   {
  314.     // This assumes order of items is Cell, Row, Column
  315.     dialog.SelectionList.selectedIndex = SelectedCellsType-1;
  316.  
  317.     var previousValue = dialog.CellHeightInput.value;
  318.     dialog.CellHeightInput.value = InitPixelOrPercentMenulist(globalCellElement, CellElement, "height", "CellHeightUnits", gPixel);
  319.     dialog.CellHeightCheckbox.checked = AdvancedEditUsed && previousValue != dialog.CellHeightInput.value;
  320.  
  321.     previousValue= dialog.CellWidthInput.value;
  322.     dialog.CellWidthInput.value = InitPixelOrPercentMenulist(globalCellElement, CellElement, "width", "CellWidthUnits", gPixel);
  323.     dialog.CellWidthCheckbox.checked = AdvancedEditUsed && previousValue != dialog.CellWidthInput.value;
  324.  
  325.     var previousIndex = dialog.CellVAlignList.selectedIndex;
  326.     var valign = globalCellElement.vAlign.toLowerCase();
  327.     if (valign == topStr)
  328.       dialog.CellVAlignList.selectedIndex = 0;
  329.     else if (valign == bottomStr)
  330.       dialog.CellVAlignList.selectedIndex = 2;
  331.     else // Default = middle
  332.       dialog.CellVAlignList.selectedIndex = 1;
  333.  
  334.     dialog.CellVAlignCheckbox.checked = AdvancedEditUsed && previousValue != dialog.CellVAlignList.selectedIndex;
  335.  
  336.  
  337.     previousIndex = dialog.CellHAlignList.selectedIndex;
  338.  
  339.     alignWasChar = false;
  340.  
  341.     var halign = globalCellElement.align.toLowerCase();
  342.     switch (halign)
  343.     {
  344.       case centerStr:
  345.         dialog.CellHAlignList.selectedIndex = 1;
  346.         break;
  347.       case rightStr:
  348.         dialog.CellHAlignList.selectedIndex = 2;
  349.         break;
  350.       case justifyStr:
  351.         dialog.CellHAlignList.selectedIndex = 3;
  352.         break;
  353.       case charStr:
  354.         // We don't support UI for this because layout doesn't work: bug 2212.
  355.         // Remember that's what they had so we don't change it
  356.         //  unless they change the alignment by using the menulist
  357.         alignWasChar = true;
  358.         // Fall through to use show default alignment in menu
  359.       default:
  360.         // Default depends on cell type (TH is "center", TD is "left")
  361.         dialog.CellHAlignList.selectedIndex =
  362.           (globalCellElement.nodeName.toLowerCase() == "th") ? 1 : 0;
  363.         break;
  364.     }
  365.  
  366.     dialog.CellHAlignCheckbox.checked = AdvancedEditUsed &&
  367.       previousIndex != dialog.CellHAlignList.selectedIndex;
  368.  
  369.     previousIndex = dialog.CellStyleList.selectedIndex;
  370.     dialog.CellStyleList.selectedIndex = (globalCellElement.nodeName.toLowerCase() == "th") ? 1 : 0;
  371.     dialog.CellStyleCheckbox.checked = AdvancedEditUsed && previousIndex != dialog.CellStyleList.selectedIndex;
  372.  
  373.     previousIndex = dialog.TextWrapList.selectedIndex;
  374.     dialog.TextWrapList.selectedIndex = globalCellElement.noWrap ? 1 : 0;
  375.     dialog.TextWrapCheckbox.checked = AdvancedEditUsed && previousIndex != dialog.TextWrapList.selectedIndex;
  376.  
  377.     previousValue = CellColor;
  378.     SetColor("cellBackgroundCW", globalCellElement.bgColor);
  379.     dialog.CellColorCheckbox.checked = AdvancedEditUsed && CellColor != globalCellElement.bgColor;
  380.     CellColor = globalCellElement.bgColor;
  381.  
  382.     // We want to set this true in case changes came
  383.     //   from Advanced Edit dialog session (must assume something changed)
  384.     CellDataChanged = true;
  385.   }
  386. }
  387.  
  388. function GetCellData(rowIndex, colIndex)
  389. {
  390.   // Get actual rowspan and colspan
  391.   var startRowIndexObj = new Object;
  392.   var startColIndexObj = new Object;
  393.   var rowSpanObj = new Object;
  394.   var colSpanObj = new Object;
  395.   var actualRowSpanObj = new Object;
  396.   var actualColSpanObj = new Object;
  397.   var isSelectedObj = new Object;
  398.   if (!cellData)
  399.     cellData = new Object;
  400.  
  401.   try {
  402.     cellData.cell =
  403.       editorShell.GetCellDataAt(TableElement, rowIndex, colIndex,
  404.                                 startRowIndexObj, startColIndexObj,
  405.                                 rowSpanObj, colSpanObj,
  406.                                 actualRowSpanObj, actualColSpanObj, isSelectedObj);
  407.     // We didn't find a cell
  408.     if (!cellData.cell) return false;
  409.   }
  410.   catch(ex) {
  411.     return false;
  412.   }
  413.  
  414.   cellData.startRowIndex = startRowIndexObj.value;
  415.   cellData.startColIndex = startColIndexObj.value;
  416.   cellData.rowSpan = rowSpanObj.value;
  417.   cellData.colSpan = colSpanObj.value;
  418.   cellData.actualRowSpan = actualRowSpanObj.value;
  419.   cellData.actualColSpan = actualColSpanObj.value;
  420.   cellData.isSelected = isSelectedObj.value;
  421.   return true;
  422. }
  423.  
  424. function SelectTableTab()
  425. {
  426.   globalElement = globalTableElement;
  427.   currentPanel = TablePanel;
  428. }
  429.  
  430. function SelectCellTab()
  431. {
  432.   globalElement = globalCellElement;
  433.   currentPanel = CellPanel;
  434. }
  435.  
  436. function SelectCellHAlign()
  437. {
  438.   SetCheckbox("CellHAlignCheckbox");
  439.   // Once user changes the alignment,
  440.   //  we loose their original "CharAt" alignment"
  441.   alignWasChar = false;
  442. }
  443.  
  444. function GetColorAndUpdate(ColorWellID)
  445. {
  446.   var colorWell = document.getElementById(ColorWellID);
  447.   if (!colorWell) return;
  448.  
  449.   var colorObj = new Object;
  450.  
  451.   switch( ColorWellID )
  452.   {
  453.     case "tableBackgroundCW":
  454.       colorObj.Type = "Table";
  455.       colorObj.TableColor = TableColor;
  456.       break;
  457.     case "cellBackgroundCW":
  458.       colorObj.Type = "Cell";
  459.       colorObj.CellColor = CellColor;
  460.       break;
  461.   }
  462.   // Avoid the JS warning
  463.   colorObj.NoDefault = false;
  464.   window.openDialog("chrome://editor/content/EdColorPicker.xul", "_blank", "chrome,close,titlebar,modal", "", colorObj);
  465.  
  466.   // User canceled the dialog
  467.   if (colorObj.Cancel)
  468.     return;
  469.  
  470.   switch( ColorWellID )
  471.   {
  472.     case "tableBackgroundCW":
  473.       TableColor = colorObj.BackgroundColor;
  474.       SetColor(ColorWellID, TableColor);
  475.       break;
  476.     case "cellBackgroundCW":
  477.       CellColor = colorObj.BackgroundColor;
  478.       SetColor(ColorWellID, CellColor);
  479.       SetCheckbox('CellColorCheckbox');
  480.       break;
  481.   }
  482. }
  483.  
  484. function SetColor(ColorWellID, color)
  485. {
  486.   // Save the color
  487.   if (ColorWellID == "cellBackgroundCW")
  488.   {
  489.     if (color)
  490.     {
  491.       globalCellElement.setAttribute(bgcolor, color);
  492.       dialog.CellInheritColor.setAttribute("collapsed","true");
  493.     }
  494.     else
  495.     {
  496.       globalCellElement.removeAttribute(bgcolor);
  497.       // Reveal addition message explaining "default" color
  498.       dialog.CellInheritColor.removeAttribute("collapsed");
  499.     }
  500.   }
  501.   else
  502.   {
  503.     if (color)
  504.     {
  505.       globalTableElement.setAttribute(bgcolor, color);
  506.       dialog.TableInheritColor.setAttribute("collapsed","true");
  507.     }
  508.     else
  509.     {
  510.       globalTableElement.removeAttribute(bgcolor);
  511.       dialog.TableInheritColor.removeAttribute("collapsed");
  512.     }
  513.     SetCheckbox('CellColorCheckbox');
  514.   }
  515.  
  516.   setColorWell(ColorWellID, color);
  517. }
  518.  
  519. function ChangeSelectionToFirstCell()
  520. {
  521.   if (!GetCellData(0,0))
  522.   {
  523.     dump("Can't find first cell in table!\n");
  524.     return;
  525.   }
  526.   CellElement = cellData.cell;
  527.   globalCellElement = CellElement;
  528.   globalElement = CellElement;
  529.  
  530.   curRowIndex = 0;
  531.   curColIndex = 0;
  532.   ChangeSelection(RESET_SELECTION);
  533. }
  534.  
  535. function ChangeSelection(newType)
  536. {
  537.   newType = Number(newType);
  538.  
  539.   if (SelectedCellsType == newType)
  540.     return;
  541.  
  542.   if (newType == RESET_SELECTION)
  543.     // Restore selection to existing focus cell
  544.     selection.collapse(CellElement,0);
  545.   else
  546.     SelectedCellsType = newType;
  547.  
  548.   // Keep the same focus CellElement, just change the type
  549.   DoCellSelection();
  550.   SetSelectionButtons();
  551.  
  552.   // Note: globalCellElement should still be a clone of CellElement
  553. }
  554.  
  555. function MoveSelection(forward)
  556. {
  557.   var newRowIndex = curRowIndex;
  558.   var newColIndex = curColIndex;
  559.   var focusCell;
  560.   var inRow = false;
  561.  
  562.   if (SelectedCellsType == SELECT_ROW)
  563.   {
  564.     newRowIndex += (forward ? 1 : -1);
  565.  
  566.     // Wrap around if before first or after last row
  567.     if (newRowIndex < 0)
  568.       newRowIndex = lastRowIndex;
  569.     else if (newRowIndex > lastRowIndex)
  570.       newRowIndex = 0;
  571.     inRow = true;
  572.  
  573.     // Use first cell in row for focus cell
  574.     newColIndex = 0;
  575.   }
  576.   else
  577.   {
  578.     // Cell or column:
  579.     if (!forward)
  580.       newColIndex--;
  581.  
  582.     if (SelectedCellsType == SELECT_CELL)
  583.     {
  584.       // Skip to next cell
  585.       if (forward)
  586.         newColIndex += curColSpan;
  587.     }
  588.     else  // SELECT_COLUMN
  589.     {
  590.       // Use first cell in column for focus cell
  591.       newRowIndex = 0;
  592.  
  593.       // Don't skip by colspan,
  594.       //  but find first cell in next cellmap column
  595.       if (forward)
  596.         newColIndex++;
  597.     }
  598.  
  599.     if (newColIndex < 0)
  600.     {
  601.       // Request is before the first cell in column
  602.  
  603.       // Wrap to last cell in column
  604.       newColIndex = lastColIndex;
  605.  
  606.       if (SelectedCellsType == SELECT_CELL)
  607.       {
  608.         // If moving by cell, also wrap to previous...
  609.         if (newRowIndex > 0)
  610.           newRowIndex -= 1;
  611.         else
  612.           // ...or the last row
  613.           newRowIndex = lastRowIndex;
  614.  
  615.         inRow = true;
  616.       }
  617.     }
  618.     else if (newColIndex > lastColIndex)
  619.     {
  620.       // Request is after the last cell in column
  621.  
  622.       // Wrap to first cell in column
  623.       newColIndex = 0;
  624.  
  625.       if (SelectedCellsType == SELECT_CELL)
  626.       {
  627.         // If moving by cell, also wrap to next...
  628.         if (newRowIndex < lastRowIndex)
  629.           newRowIndex++;
  630.         else
  631.           // ...or the first row
  632.           newRowIndex = 0;
  633.  
  634.         inRow = true;
  635.       }
  636.     }
  637.   }
  638.  
  639.   // Get the cell at the new location
  640.   do {
  641.     if (!GetCellData(newRowIndex, newColIndex))
  642.     {
  643.       dump("MoveSelection: CELL NOT FOUND\n");
  644.       return;
  645.     }
  646.     if (inRow)
  647.     {
  648.       if (cellData.startRowIndex == newRowIndex)
  649.         break;
  650.       else
  651.         // Cell spans from a row above, look for the next cell in row
  652.         newRowIndex += cellData.actualRowSpan;
  653.     }
  654.     else
  655.     {
  656.       if (cellData.startColIndex == newColIndex)
  657.         break;
  658.       else
  659.         // Cell spans from a Col above, look for the next cell in column
  660.         newColIndex += cellData.actualColSpan;
  661.     }
  662.   }
  663.   while(true);
  664.  
  665.   // Save data for current selection before changing
  666.   if (CellDataChanged) // && dialog.ApplyBeforeMove.checked)
  667.   {
  668.     if (!ValidateCellData())
  669.       return;
  670.  
  671.     editorShell.BeginBatchChanges();
  672.     // Apply changes to all selected cells
  673.     ApplyCellAttributes();
  674.     editorShell.EndBatchChanges();
  675.  
  676.     SetCloseButton();
  677.   }
  678.  
  679.   // Set cell and other data for new selection
  680.   CellElement = cellData.cell;
  681.  
  682.   // Save globals for new current cell
  683.   curRowIndex = cellData.startRowIndex;
  684.   curColIndex = cellData.startColIndex;
  685.   curColSpan = cellData.actualColSpan;
  686.  
  687.   // Copy for new global cell
  688.   globalCellElement = CellElement.cloneNode(false);
  689.   globalElement = globalCellElement;
  690.  
  691.   // Change the selection
  692.   DoCellSelection();
  693.  
  694.   // Reinitialize dialog using new cell
  695. //  if (!dialog.KeepCurrentData.checked)
  696.   // Setting this false unchecks all "set attributes" checkboxes
  697.   AdvancedEditUsed = false;
  698.   InitCellPanel();
  699.   AdvancedEditUsed = true;
  700. }
  701.  
  702.  
  703. function DoCellSelection()
  704. {
  705.   // Collapse selection into to the focus cell
  706.   //  so editor uses that as start cell
  707.   selection.collapse(CellElement, 0);
  708.  
  709.   switch (SelectedCellsType)
  710.   {
  711.     case SELECT_CELL:
  712.       editorShell.SelectTableCell();
  713.       break
  714.     case SELECT_ROW:
  715.       editorShell.SelectTableRow();
  716.       break;
  717.     default:
  718.       editorShell.SelectTableColumn();
  719.       break;
  720.   }
  721.   // Get number of cells selected
  722.   var tagNameObj = new Object;
  723.   var countObj = new Object;
  724.   tagNameObj.value = "";
  725.   var tableOrCellElement = editorShell.GetSelectedOrParentTableElement(tagNameObj, countObj);
  726.   if (tagNameObj.value == "td")
  727.     gSelectedCellCount = countObj.value;
  728.   else
  729.     gSelectedCellCount = 0;
  730.  
  731.   // Currently, we can only allow advanced editing on ONE cell element at a time
  732.   //   else we ignore CSS, JS, and HTML attributes not already in dialog
  733.   SetElementEnabledById("AdvancedEditButton2", gSelectedCellCount == 1);
  734. }
  735.  
  736. function SetSelectionButtons()
  737. {
  738.   if (SelectedCellsType == SELECT_ROW)
  739.   {
  740.     // Trigger CSS to set images of up and down arrows
  741.     dialog.PreviousButton.setAttribute("type","row");
  742.     dialog.NextButton.setAttribute("type","row");
  743.   }
  744.   else
  745.   {
  746.     // or images of left and right arrows
  747.     dialog.PreviousButton.setAttribute("type","col");
  748.     dialog.NextButton.setAttribute("type","col");
  749.   }
  750.   DisableSelectionButtons((SelectedCellsType == SELECT_ROW && rowCount == 1) ||
  751.                           (SelectedCellsType == SELECT_COLUMN && colCount == 1) ||
  752.                           (rowCount == 1 && colCount == 1));
  753. }
  754.  
  755. function DisableSelectionButtons( disable )
  756. {
  757.   dialog.PreviousButton.setAttribute("disabled", disable ? "true" : "false");
  758.   dialog.NextButton.setAttribute("disabled", disable ? "true" : "false");
  759. }
  760.  
  761. function SwitchToValidatePanel()
  762. {
  763.   if (currentPanel != validatePanel)
  764.   {
  765.     //Set index for starting panel on the <tabpanels> element
  766.     TabPanels.setAttribute("index", validatePanel);
  767.     if (validatePanel == CellPanel)
  768.     {
  769.       // Trigger setting of style for the tab widgets
  770.       CellTab.setAttribute("selected", "true");
  771.       TableTab.removeAttribute("selected");
  772.     } else {
  773.       TableTab.setAttribute("selected", "true");
  774.       CellTab.removeAttribute("selected");
  775.     }
  776.     currentPanel = validatePanel;
  777.   }
  778. }
  779.  
  780. function SetAlign(listID, defaultValue, element, attName)
  781. {
  782.   var value = document.getElementById(listID).selectedItem.value;
  783.   if (value == defaultValue)
  784.     element.removeAttribute(attName);
  785.   else
  786.     element.setAttribute(attName, value);
  787. }
  788.  
  789. function ValidateTableData()
  790. {
  791.   validatePanel = TablePanel;
  792.   newRowCount = Number(ValidateNumber(dialog.TableRowsInput, null, 1, maxRows, null, null, true));
  793.   if (gValidationError) return false;
  794.  
  795.   newColCount = Number(ValidateNumber(dialog.TableColumnsInput, null, 1, maxColumns, null, null, true));
  796.   if (gValidationError) return false;
  797.  
  798.  
  799.   ValidateNumber(dialog.TableWidthInput, dialog.TableWidthUnits,
  800.                  1, maxPixels, globalTableElement, "width");
  801.   if (gValidationError) return false;
  802.  
  803.   var border = ValidateNumber(dialog.BorderWidthInput, null, 0, maxPixels, globalTableElement, "border");
  804.   // TODO: Deal with "BORDER" without value issue
  805.   if (gValidationError) return false;
  806.  
  807.   ValidateNumber(dialog.SpacingInput, null, 0, maxPixels, globalTableElement, "cellspacing");
  808.   if (gValidationError) return false;
  809.  
  810.   ValidateNumber(dialog.PaddingInput, null, 0, maxPixels, globalTableElement, "cellpadding");
  811.   if (gValidationError) return false;
  812.  
  813.   SetAlign("TableAlignList", defHAlign, globalTableElement, "align");
  814.  
  815.   // Color is set on globalCellElement immediately
  816.   return true;
  817. }
  818.  
  819. function ValidateCellData()
  820. {
  821.  
  822.   validatePanel = CellPanel;
  823.  
  824.   if (dialog.CellHeightCheckbox.checked)
  825.   {
  826.     ValidateNumber(dialog.CellHeightInput, dialog.CellHeightUnits,
  827.                     1, maxPixels, globalCellElement, "height");
  828.     if (gValidationError) return false;
  829.   }
  830.  
  831.   if (dialog.CellWidthCheckbox.checked)
  832.   {
  833.     ValidateNumber(dialog.CellWidthInput, dialog.CellWidthUnits,
  834.                    1, maxPixels, globalCellElement, "width");
  835.     if (gValidationError) return false;
  836.   }
  837.  
  838.   if (dialog.CellHAlignCheckbox.checked)
  839.   {
  840.     var hAlign = dialog.CellHAlignList.selectedItem.value;
  841.  
  842.     // Horizontal alignment is complicated by "char" type
  843.     // We don't change current values if user didn't edit alignment
  844.     if (!alignWasChar)
  845.     {
  846.       globalCellElement.removeAttribute(charStr);
  847.  
  848.       // Always set "align" attribute,
  849.       //  so the default "left" is effective in a cell
  850.       //  when parent row has align set.
  851.       globalCellElement.setAttribute("align", hAlign);
  852.     }
  853.   }
  854.  
  855.   if (dialog.CellVAlignCheckbox.checked)
  856.   {
  857.     // Always set valign (no default in 2nd param) so
  858.     //  the default "middle" is effective in a cell
  859.     //  when parent row has valign set.
  860.     SetAlign("CellVAlignList", "", globalCellElement, "valign");
  861.   }
  862.  
  863.   if (dialog.TextWrapCheckbox.checked)
  864.   {
  865.     if (dialog.TextWrapList.selectedIndex == 1)
  866.       globalCellElement.setAttribute("nowrap","true");
  867.     else
  868.       globalCellElement.removeAttribute("nowrap");
  869.   }
  870.  
  871.   return true;
  872. }
  873.  
  874. function ValidateData()
  875. {
  876.   var result;
  877.   var savePanel = currentPanel;
  878.  
  879.   // Validate current panel first
  880.   if (currentPanel == TablePanel)
  881.   {
  882.     result = ValidateTableData();
  883.     if (result)
  884.       result = ValidateCellData();
  885.   } else {
  886.     result = ValidateCellData();
  887.     if (result)
  888.       result = ValidateTableData();
  889.   }
  890.   if(!result) return false;
  891.  
  892.   // If we passed, restore former currentPanel
  893.   currentPanel = savePanel;
  894.  
  895.   // Set global element for AdvancedEdit
  896.   if(currentPanel == TablePanel)
  897.     globalElement = globalTableElement;
  898.   else
  899.     globalElement = globalCellElement;
  900.  
  901.   return true;
  902. }
  903.  
  904. function ChangeCellTextbox(textboxID)
  905. {
  906.   // Filter input for just integers
  907.   forceInteger(textboxID);
  908.  
  909.   if (currentPanel == CellPanel)
  910.     CellDataChanged = true;
  911. }
  912.  
  913. // Call this when a textbox or menulist is changed
  914. //   so the checkbox is automatically set
  915. function SetCheckbox(checkboxID)
  916. {
  917.   if (checkboxID && checkboxID.length > 0)
  918.   {
  919.     // Set associated checkbox
  920.     document.getElementById(checkboxID).checked = true;
  921.   }
  922.   CellDataChanged = true;
  923. }
  924.  
  925. function ChangeIntTextbox(textboxID, checkboxID)
  926. {
  927.   // Filter input for just integers
  928.   forceInteger(textboxID);
  929.  
  930.   // Set associated checkbox
  931.   SetCheckbox(checkboxID);
  932. }
  933.  
  934. function CloneAttribute(destElement, srcElement, attr)
  935. {
  936.   var value = srcElement.getAttribute(attr);
  937.  
  938.   // Use editorShell methods since we are always
  939.   //  modifying a table in the document and
  940.   //  we need transaction system for undo
  941.   if (!value || value.length == 0)
  942.     editorShell.RemoveAttribute(destElement, attr);
  943.   else
  944.     editorShell.SetAttribute(destElement, attr, value);
  945. }
  946.  
  947. function ConfirmDeleteCells()
  948. {
  949.   if (0 == editorShell.ConfirmWithTitle(GetString("DeleteTableTitle"), GetString("DeleteTableMsg"),
  950.                                         GetString("DeleteCells"), ""))
  951.   {
  952.     return true;
  953.   }
  954.   return false;
  955. }
  956.  
  957. function ApplyTableAttributes()
  958. {
  959.   var newAlign = dialog.TableCaptionList.selectedItem.value;
  960.   if (!newAlign) newAlign = "";
  961.  
  962.   if (TableCaptionElement)
  963.   {
  964.     // Get current alignment
  965.     var align = TableCaptionElement.align.toLowerCase();
  966.     // This is the default
  967.     if (!align) align = "top";
  968.  
  969.     if (newAlign == "")
  970.     {
  971.       // Remove existing caption
  972.       editorShell.DeleteElement(TableCaptionElement);
  973.       TableCaptionElement = null;
  974.     }
  975.     else if( align != newAlign)
  976.     {
  977.       if (align == "top") // This is default, so don't explicitly set it
  978.         editorShell.RemoveAttribute(TableCaptionElement, "align");
  979.       else
  980.         editorShell.SetAttribute(TableCaptionElement, "align", newAlign);
  981.     }
  982.   }
  983.   else if (newAlign != "")
  984.   {
  985.     // Create and insert a caption:
  986.     TableCaptionElement = editorShell.CreateElementWithDefaults("caption");
  987.     if (TableCaptionElement)
  988.     {
  989.       if (newAlign != "top")
  990.         TableCaptionElement.setAttribute("align", newAlign);
  991.  
  992.       // Insert it into the table - caption is always inserted as first child
  993.       editorShell.InsertElement(TableCaptionElement, TableElement, 0, true);
  994.  
  995.       // Put selecton back where it was
  996.       ChangeSelection(RESET_SELECTION);
  997.     }
  998.   }
  999.  
  1000.   var countDelta;
  1001.   var foundcell;
  1002.   var i;
  1003.  
  1004.   // If user is deleting any cells and get confirmation
  1005.   // (This is a global to the dialog and we ask only once per dialog session)
  1006.   if ( !canDelete &&
  1007.        (newRowCount < rowCount ||
  1008.         newColCount < colCount) &&
  1009.        ConfirmDeleteCells() )
  1010.   {
  1011.     canDelete = true;
  1012.   }
  1013.  
  1014.   if (newRowCount != rowCount)
  1015.   {
  1016.     countDelta = newRowCount - rowCount;
  1017.     if (newRowCount > rowCount)
  1018.     {
  1019.       // Append new rows
  1020.       // Find first cell in last row
  1021.       if(GetCellData(lastRowIndex, 0))
  1022.       {
  1023.         try {
  1024.           // Move selection to the last cell
  1025.           selection.collapse(cellData.cell,0);
  1026.           // Insert new rows after it
  1027.           editorShell.InsertTableRow(countDelta, true);
  1028.           rowCount = newRowCount;
  1029.           lastRowIndex = rowCount - 1;
  1030.           // Put selecton back where it was
  1031.           ChangeSelection(RESET_SELECTION);
  1032.         }
  1033.         catch(ex) {
  1034.           dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
  1035.         }
  1036.       }
  1037.     }
  1038.     else
  1039.     {
  1040.       // Delete rows
  1041.       if (canDelete)
  1042.       {
  1043.         // Find first cell starting in first row we delete
  1044.         var firstDeleteRow = rowCount + countDelta;
  1045.         foundCell = false;
  1046.         for ( i = 0; i <= lastColIndex; i++)
  1047.         {
  1048.           if (!GetCellData(firstDeleteRow, i))
  1049.             break; // We failed to find a cell
  1050.  
  1051.           if (cellData.startRowIndex == firstDeleteRow)
  1052.           {
  1053.             foundCell = true;
  1054.             break;
  1055.           }
  1056.         };
  1057.         if (foundCell)
  1058.         {
  1059.           try {
  1060.             // Move selection to the cell we found
  1061.             selection.collapse(cellData.cell, 0);
  1062.             editorShell.DeleteTableRow(-countDelta);
  1063.             rowCount = newRowCount;
  1064.             lastRowIndex = rowCount - 1;
  1065.             if (curRowIndex > lastRowIndex)
  1066.               // We are deleting our selection
  1067.               // move it to start of table
  1068.               ChangeSelectionToFirstCell()
  1069.             else
  1070.               // Put selecton back where it was
  1071.               ChangeSelection(RESET_SELECTION);
  1072.           }
  1073.           catch(ex) {
  1074.             dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
  1075.           }
  1076.         }
  1077.       }
  1078.     }
  1079.   }
  1080.  
  1081.   if (newColCount != colCount)
  1082.   {
  1083.     countDelta = newColCount - colCount;
  1084.  
  1085.     if (newColCount > colCount)
  1086.     {
  1087.       // Append new columns
  1088.       // Find last cell in first column
  1089.       if(GetCellData(0, lastColIndex))
  1090.       {
  1091.         try {
  1092.           // Move selection to the last cell
  1093.           selection.collapse(cellData.cell,0);
  1094.           editorShell.InsertTableColumn(countDelta, true);
  1095.           colCount = newColCount;
  1096.           lastColIndex = colCount-1;
  1097.           // Restore selection
  1098.           ChangeSelection(RESET_SELECTION);
  1099.         }
  1100.         catch(ex) {
  1101.           dump("FAILED TO FIND FIRST CELL IN LAST COLUMN\n");
  1102.         }
  1103.       }
  1104.     }
  1105.     else
  1106.     {
  1107.       // Delete columns
  1108.       if (canDelete)
  1109.       {
  1110.         var firstDeleteCol = colCount + countDelta;
  1111.         foundCell = false;
  1112.         for ( i = 0; i <= lastRowIndex; i++)
  1113.         {
  1114.           // Find first cell starting in first column we delete
  1115.           if (!GetCellData(i, firstDeleteCol))
  1116.             break; // We failed to find a cell
  1117.  
  1118.           if (cellData.startColIndex == firstDeleteCol)
  1119.           {
  1120.             foundCell = true;
  1121.             break;
  1122.           }
  1123.         };
  1124.         if (foundCell)
  1125.         {
  1126.           try {
  1127.             // Move selection to the cell we found
  1128.             selection.collapse(cellData.cell, 0);
  1129.             editorShell.DeleteTableColumn(-countDelta);
  1130.             colCount = newColCount;
  1131.             lastColIndex = colCount-1;
  1132.             if (curColIndex > lastColIndex)
  1133.               ChangeSelectionToFirstCell()
  1134.             else
  1135.               ChangeSelection(RESET_SELECTION);
  1136.           }
  1137.           catch(ex) {
  1138.             dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
  1139.           }
  1140.         }
  1141.       }
  1142.     }
  1143.   }
  1144.  
  1145.   // Clone all remaining attributes to pick up
  1146.   //  anything changed by Advanced Edit Dialog
  1147.   editorShell.CloneAttributes(TableElement, globalTableElement);
  1148. }
  1149.  
  1150. function ApplyCellAttributes()
  1151. {
  1152.   var selectedCell = editorShell.GetFirstSelectedCell();
  1153.   if (!selectedCell)
  1154.     return;
  1155.  
  1156.   if (gSelectedCellCount == 1)
  1157.   {
  1158.     // When only one cell is selected, simply clone entire element,
  1159.     //  thus CSS and JS from Advanced edit is copied
  1160.     editorShell.CloneAttributes(selectedCell, globalCellElement);
  1161.  
  1162.     if (dialog.CellStyleCheckbox.checked)
  1163.     {
  1164.       var currentStyleIndex = (selectedCell.nodeName.toLowerCase() == "th") ? 1 : 0;
  1165.       if (dialog.CellStyleList.selectedIndex != currentStyleIndex)
  1166.       {
  1167.         // Switch cell types
  1168.         // (replaces with new cell and copies attributes and contents)
  1169.         selectedCell = editorShell.SwitchTableCellHeaderType(selectedCell);
  1170.       }
  1171.     }
  1172.   }
  1173.   else
  1174.   {
  1175.     // Apply changes to all selected cells
  1176.     //XXX THIS DOESN'T COPY ADVANCED EDIT CHANGES!
  1177.     while (selectedCell)
  1178.     {
  1179.       ApplyAttributesToOneCell(selectedCell);
  1180.       selectedCell = editorShell.GetNextSelectedCell();
  1181.     }
  1182.   }
  1183.   CellDataChanged = false;
  1184. }
  1185.  
  1186. function ApplyAttributesToOneCell(destElement)
  1187. {
  1188.   if (dialog.CellHeightCheckbox.checked)
  1189.     CloneAttribute(destElement, globalCellElement, "height");
  1190.  
  1191.   if (dialog.CellWidthCheckbox.checked)
  1192.     CloneAttribute(destElement, globalCellElement, "width");
  1193.  
  1194.   if (dialog.CellHAlignCheckbox.checked)
  1195.   {
  1196.     CloneAttribute(destElement, globalCellElement, "align");
  1197.     CloneAttribute(destElement, globalCellElement, charStr);
  1198.   }
  1199.  
  1200.   if (dialog.CellVAlignCheckbox.checked)
  1201.     CloneAttribute(destElement, globalCellElement, "valign");
  1202.  
  1203.   if (dialog.TextWrapCheckbox.checked)
  1204.     CloneAttribute(destElement, globalCellElement, "nowrap");
  1205.  
  1206.   if (dialog.CellStyleCheckbox.checked)
  1207.   {
  1208.     var newStyleIndex = dialog.CellStyleList.selectedIndex;
  1209.     var currentStyleIndex = (destElement.nodeName.toLowerCase() == "th") ? 1 : 0;
  1210.  
  1211.     if (newStyleIndex != currentStyleIndex)
  1212.     {
  1213.       // Switch cell types
  1214.       // (replaces with new cell and copies attributes and contents)
  1215.       destElement = editorShell.SwitchTableCellHeaderType(destElement);
  1216.     }
  1217.   }
  1218.  
  1219.   if (dialog.CellColorCheckbox.checked)
  1220.     CloneAttribute(destElement, globalCellElement, "bgcolor");
  1221. }
  1222.  
  1223. function SetCloseButton()
  1224. {
  1225.   // Change text on "Cancel" button after Apply is used
  1226.   if (!ApplyUsed)
  1227.   {
  1228.     document.getElementById("cancel").setAttribute("label",GetString("Close"));
  1229.     ApplyUsed = true;
  1230.   }
  1231. }
  1232.  
  1233. function onApply()
  1234. {
  1235.   Apply();
  1236.   return false; // don't close window
  1237. }
  1238.  
  1239. function Apply()
  1240. {
  1241.   if (ValidateData())
  1242.   {
  1243.     editorShell.BeginBatchChanges();
  1244.  
  1245.     ApplyTableAttributes();
  1246.  
  1247.     // We may have just a table, so check for cell element
  1248.     if (globalCellElement)
  1249.       ApplyCellAttributes();
  1250.  
  1251.     editorShell.EndBatchChanges();
  1252.  
  1253.     SetCloseButton();
  1254.     return true;
  1255.   }
  1256.   return false;
  1257. }
  1258.  
  1259. function doHelpButton()
  1260. {
  1261.   openHelp("chrome://help/content/help.xul?table_properties");
  1262. }
  1263.  
  1264. function onOK()
  1265. {
  1266.   // Do same as Apply and close window if ValidateData succeeded
  1267.   var retVal = Apply();
  1268.   if (retVal)
  1269.     SaveWindowLocation();
  1270.  
  1271.   return retVal;
  1272. }
  1273.